package com.culture.config.component;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.culture.config.common.util.FunctionUtil;
import com.culture.config.dao.entity.App;
import com.culture.config.dao.entity.Property;
import com.culture.config.dao.mapper.AppMapper;
import com.culture.config.dao.mapper.PropertyMapper;
import com.culture.config.model.po.PropertiesUpdateParam;
import com.culture.config.model.po.PropertySyncPO;
import com.culture.config.util.Base64Util;
import com.culture.config.util.PropertiesUtil;
import com.culture.config.wrapper.PropertyWrapper;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class PropertyWorker {
    @Resource
	private AppMapper appMapper;
    @Resource
	private PropertyMapper propertyMapper;

	public List<Property> getConfigProperties(App app, String profile, String label){
		List<Property> propertyList = this.propertyMapper.listByApp(PropertyWrapper.wrapPropertyQuery(app,profile, label));	
		return FunctionUtil.filter(propertyList, e->e.getDeleted() == 0);
	}

	public void update(Property oldProperty,String value){
		Property updateProperty = PropertyWrapper.wrapPropertyUpdate(oldProperty,value);
		this.propertyMapper.update(updateProperty);
	}

	public void add(App app, Property newProperty,PropertiesUpdateParam param){
		Property propertyAdd = PropertyWrapper.wrapPropertyAdd(app,newProperty,param);
		this.propertyMapper.add(propertyAdd);
	}

	public void updateProperties(App app, PropertiesUpdateParam param){
		List<Property> properties = this.propertyMapper.listByApp(PropertyWrapper.wrapPropertyQuery(param));
		Map<String,Property> propertyMap = FunctionUtil.toMap(properties, Property::getPropertyKey);	 
		List<Property> updateProperties = PropertiesUtil.ymlToProperties(Base64Util.decodeToString(param.getYaml()));
		updateProperties.forEach(e->{
			Property old = propertyMap.get(e.getPropertyKey());
			if(Objects.nonNull(old)){
				this.update(old, e.getPropertyValue());
				return;
			}
			this.add(app,e,param);
		});
	}

    public void syncProperty(PropertySyncPO syncPO) {
		if(StringUtils.endsWithIgnoreCase(syncPO.getProfile(), syncPO.getTargetProfile()) 
				&& StringUtils.endsWithIgnoreCase(syncPO.getLabel(), syncPO.getTargetLabel())){
			return;
		}
		App app = this.appMapper.get(syncPO.getAppId());
		List<Property> propertyList = this.propertyMapper.listByApp(PropertyWrapper.wrapPropertyQuery(app, syncPO.getProfile(), syncPO.getLabel()));
		if(CollectionUtils.isEmpty(propertyList)){
			return;
		}				
		List<Property> targetPropertyList = Optional.ofNullable(this.propertyMapper.listByApp(PropertyWrapper.wrapPropertyQuery(app, syncPO.getTargetProfile(), syncPO.getTargetLabel())))
				.orElse(Collections.emptyList());
		Map<String,List<Property>> targetPropertyMap = targetPropertyList.stream().collect(Collectors.groupingBy(item->{
			return StringUtils.join(item.getProfile(),item.getLabel());
		}));
        propertyList.forEach(e->{
			String pKey = StringUtils.join(e.getProfile(),e.getLabel());
			List<Property> tProperties = targetPropertyMap.get(pKey);
			if(CollectionUtils.isEmpty(tProperties)){			
				Property newProperty = PropertyWrapper.wrapPropertyCopy(e,syncPO);	
				this.propertyMapper.add(newProperty);
				log.info("syncProperty add:{}",newProperty);
				return;
			}
			tProperties.forEach(t->{
				Property updateProperty = PropertyWrapper.wrapPropertyCopyUpdate(e, t);
				this.propertyMapper.update(updateProperty);
				log.info("syncProperty update:{}",updateProperty);
			});
		});		
	}	
}
